package com.sl.plugin.step.field;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sl.core.engine.meta.impl.AbstractProcessCompDescriptor;
import com.sl.core.engine.step.ProcessCompService;
import com.sl.core.engine.step.impl.AbstractProcessComp;
import com.sl.core.engine.utils.BeanUtil;
import org.noear.snack.ONode;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 */
//@Compensation(listener = NormalRowListener.class, type = CompensationType.SERVICE_COMPENSATION)
public class FieldSplitComp extends AbstractProcessComp<Map<String, Object>, Object> implements ProcessCompService {

    public FieldSplitComp(AbstractProcessCompDescriptor abstractProcessCompDescriptor) {
        super(abstractProcessCompDescriptor);
    }


    @Override
    public Object input(Map<String, Object> param) {

        Map<String, Object> am = meta.getAttributeMap();


        Boolean jsonSplitFlag = BeanUtil.getBool(am, "config.jsonSplitFlag");
        if (BooleanUtil.isTrue(jsonSplitFlag)) {
            Object object = jsonSplitBy(param);
            return object;
        }
        Boolean levelSplitFlag = BeanUtil.getBool(am, "config.levelSplitFlag");
        Integer level = BeanUtil.getInteger(am, "config.level");
        if (BooleanUtil.isTrue(levelSplitFlag) && ObjectUtil.isNotNull(level)) {
            return levelSplitBy(param, 0, level);
        }

        Boolean jsonPathSplitFlag = BeanUtil.getBool(am, "config.jsonPathSplitFlag");
        String jsonPath = BeanUtil.getStr(am, "config.jsonPath");
        if (BooleanUtil.isTrue(jsonPathSplitFlag) && StrUtil.isNotBlank(jsonPath)) {
            ONode oNode = ONode.loadObj(param);
            Object value = oNode.select(jsonPath).toObject();
            return value;
        }
        return param;
    }


    private Map<String, Object> levelSplitBy(Map<String, Object> params, Integer level, Integer maxLevel) {

        ++level;
        Map<String, Object> map = Maps.newHashMap();

        Set<String> strings = params.keySet();

        for (String valueMeta : strings) {
            Object o = params.get(valueMeta);

            if (o instanceof Collection valueMetaArray) {

                List<Object> iValueMetas = Lists.newArrayList();
                for (Object object : valueMetaArray) {
                    if (object instanceof Map mm) {
                        Map<String, Object> im = levelSplitBy(mm, level, maxLevel);
                        iValueMetas.add(im);
                    } else {
                        if (level.equals(maxLevel)) {
                            iValueMetas.add(object);
                        }
                    }

                }
                if (CollUtil.isNotEmpty(iValueMetas)) {
                    map.put(valueMeta, iValueMetas);
                }
            } else if (o instanceof Map valueMetaObject) {
                Map<String, Object> iValueMetas = levelSplitBy(valueMetaObject, level, maxLevel);
                if (MapUtil.isNotEmpty(iValueMetas)) {
                    map.putAll(iValueMetas);
                }
            } else {
                if (level.equals(maxLevel)) {
                    map.put(valueMeta, o);
                }
            }
        }
        return map;
    }

    private Map<String, Object> jsonSplitBy(Map<String, Object> param) {

        Map<String, Object> result = Maps.newHashMap();

        Set<String> strings = param.keySet();

        for (String valueMeta : strings) {
            Object o = param.get(valueMeta);

            if (o instanceof Map m) {
                Map<String, Object> iValueMetas = jsonSplitBy(m);
                result.putAll(iValueMetas);

            } else if (o instanceof Collection<?> c) {
                List<Object> cb = Lists.newArrayList();
                for (Object object : c) {
                    if (object instanceof Map map) {
                        Map<String, Object> im = jsonSplitBy(map);
                        result.putAll(im);
                    } else {
                        cb.add(object);
                    }
                }
                if (CollUtil.isNotEmpty(cb)) {
                    result.put(valueMeta, cb);
                }
            } else {
                result.put(valueMeta, o);
            }
        }
        return result;
    }

}
